//
// Copyright (c) 2010 Alex Nesterenko
//

#ifndef NANE_FACTORY_H
#    define NANE_FACTORY_H

#    include <map>

namespace nane
{

    template<class TProduct>
    struct Factory
    {
        typedef TProduct* (*TFactoryCreateMethod)();
    };

    template<class TProduct, class TBaseProduct = TProduct>
    struct FactoryNew
        : public Factory<TBaseProduct>
    {
        static TProduct* create()
        {
            return new TProduct();
        }
    };

    template<typename TID, typename TBaseProduct
            , class TMap = std::map<TID, typename Factory<TBaseProduct>::TFactoryCreateMethod> >
    class AbstractFactory
    {
    public:
        typedef Factory<TBaseProduct> TFactory;

        bool registerFactory( const TID& _id, typename TFactory::TFactoryCreateMethod _factoryMethod )
        {
            typename TMap::iterator it_find = m_factories.find( _id );
            if( it_find != m_factories.end() )
            {
                return false;
            }

            m_factories.insert( std::make_pair( _id, _factoryMethod ) );
            return true;
        }

        TFactory* unregisterFactory( const TID& _id )
        {
            TFactory* factory = NULL;
            typename TMap::iterator it_find = m_factories.find( _id );
            if( it_find != m_factories.end() )
            {
                factory = it_find->second;
                m_factories.erase( it_find );
            }
            return factory;
        }

        TBaseProduct* create( const TID& _id )
        {
            typename TMap::iterator it_find = m_factories.find( _id );
            if( it_find != m_factories.end() )
            {
                return (*it_find->second)();
            }
            return NULL;
        }

    private:
        TMap m_factories;
    };
}   // namespace nane

#endif	// NANE_FACTORY_H
